#include "StdAfx.h"
#include "Primitive.h"

using namespace std;

namespace FEngine
{
	Primitive::Primitive()
		: Node()
	{
		mIsGenerated		= false;
		mColor				= ColorRGB(255, 255, 255);
		mNumberPrimitives	= 0;
		mNumberVertices		= 0;
		mVertexBuffer		= NULL;
		mVertexDeclaration	= NULL;
		mIndexBuffer		= NULL;
	}

	Primitive::~Primitive()
	{
		if (mVertexBuffer)
			mVertexBuffer->Release();
		if (mVertexDeclaration)
			mVertexDeclaration->Release();
		if (mIndexBuffer)
			mIndexBuffer->Release();
	}

	void Primitive::_createGeometry(const vector<Vector3>& _verticesVector, const vector<unsigned int>& _indexesVector, D3DPRIMITIVETYPE _primitiveType)
	{
		if (mIsGenerated)
			return;

		if (_primitiveType != D3DPT_TRIANGLELIST && _primitiveType != D3DPT_LINELIST)
			throw FEngineException("Primitive", "_createGeometry", "The PrimitiveType is not managed");
		mPrimitiveType = _primitiveType;
		
		// Get the vertices
		FE_VERTEX* vertices = new FE_VERTEX[_verticesVector.size()];
		for (unsigned int n = 0; n < _verticesVector.size(); ++n)
			vertices[n].POSITION = _verticesVector[n];
		mNumberVertices = _verticesVector.size();
		unsigned int verticesSize = mNumberVertices * sizeof(FE_VERTEX);
		
		// Get the indexes
		short* indexes = new short[_indexesVector.size()];
		for (unsigned int n = 0; n < _indexesVector.size(); ++n)
			indexes[n] = (short)_indexesVector[n];
		
		if (mPrimitiveType == D3DPT_TRIANGLELIST)
			mNumberPrimitives = _indexesVector.size() / 3;
		if (mPrimitiveType == D3DPT_LINELIST)
			mNumberPrimitives = _indexesVector.size() / 2;
		unsigned int indexesSize = _indexesVector.size() * sizeof(short);

		// Create the vertex buffer
		CoreEngine::getInstance()->getDeviceInterface()->CreateVertexBuffer(verticesSize, D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &mVertexBuffer, NULL);

		// Create the index buffer
		CoreEngine::getInstance()->getDeviceInterface()->CreateIndexBuffer(indexesSize, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &mIndexBuffer, NULL);

		VOID* pVoid;

		// Copy the vertex buffer data into memory
		mVertexBuffer->Lock(0, 0, (void**)&pVoid, 0);
		memcpy(pVoid, vertices, verticesSize);
		mVertexBuffer->Unlock();
		
		// Copy the index buffer data into memory
		mIndexBuffer->Lock(0, 0, (void**)&pVoid, 0);
		memcpy(pVoid, indexes, indexesSize);
		mIndexBuffer->Unlock();
		
		// Load the vertex declaration
		CoreEngine::getInstance()->getDeviceInterface()->CreateVertexDeclaration(VertexDeclaration, &mVertexDeclaration);

		mIsGenerated = true;
	}
	
	void Primitive::setColor(const ColorRGB& _color)
	{
		mColor = _color;
	}
	
	void Primitive::setColor(unsigned char _red, unsigned char _green, unsigned char _blue)
	{
		mColor = ColorRGB(_red, _green, _blue);
	}
	
	ColorRGB Primitive::getColor() const
	{
		return mColor;
	}
	
	void Primitive::update(double _elapsedTime)
	{
		Node::update(_elapsedTime);
	}

	void Primitive::render(double _elapsedTime)
	{
		Node::render(_elapsedTime);

		if (!mIsGenerated)
			return;
		
		LPD3DXEFFECT shader = CoreEngine::getInstance()->getShaderEffect();
		IDirect3DDevice9* device = CoreEngine::getInstance()->getDeviceInterface();

		D3DXMATRIX spaceMat = _getWorldMatrix();
		D3DXMATRIX matWVP = spaceMat * CoreEngine::getInstance()->getCamera()->_getMatrixView() * CoreEngine::getInstance()->getCamera()->_getMatrixProjection();

		if (shader->SetTechnique(shader->GetTechniqueByName("Primitive")) != D3D_OK)
			throw FEngineException("Primitive", "render", "Unknown shader technique");
		if (shader->SetVector(shader->GetParameterByName(NULL, "gPrimitiveColor"), &mColor.toShaderFormat()) != D3D_OK)
			throw FEngineException("Primitive", "render", "Unknown shader paramater");
		if (shader->SetMatrix(shader->GetParameterByName(NULL, "gWorldViewProj"), &matWVP) != D3D_OK)
			throw FEngineException("Primitive", "render", "Unknown shader parameter");
		shader->CommitChanges();
		
		device->SetVertexDeclaration(mVertexDeclaration);
		device->SetStreamSource(0, mVertexBuffer, 0, sizeof(FE_VERTEX));
		device->SetIndices(mIndexBuffer);
		
		unsigned int cPasses, iPass;
		shader->Begin(&cPasses, 0);
		for (iPass= 0; iPass< cPasses; ++iPass)
		{
			shader->BeginPass(iPass);
			CoreEngine::getInstance()->getDeviceInterface()->DrawIndexedPrimitive(mPrimitiveType, 0, 0, mNumberVertices, 0, mNumberPrimitives);
			shader->EndPass();
		}
		shader->End();
	}


} // namespace FEngine
